/**
 *
 * @author Alex & Umit
 */
public class DLList implements PositionList {

    private DNode header;
    private DNode trailer;
    private int size;

    public DLList(){
        size = 0;
        header = new DNode(null, null, null);
        trailer = new DNode(null, null, null);
        header.setNext(trailer);
        trailer.setPrev(header);
    }

    //Not sure if it works
    public DNode checkPosition(Position p) throws InvalidPositionException{
        boolean found = false;
        DNode node = header;
        if(p != null){
            while((node.next() != trailer && !found)){
                if (node.next() == p){
                    node = node.next();
                    found = true;
                }
                else{
                    node = node.next();
                }
            }
        }
        else{
            throw new InvalidPositionException();
        }
        if(found){
            return node;
        }
        else return null;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    public Position first() throws EmptyListException{
        if(!isEmpty()){
            return header.next();
        }
        else throw new EmptyListException();
    }

    public Position last() throws EmptyListException{
        if(!isEmpty()){
            return trailer.prev();
        }
        else throw new EmptyListException();
    }

    //use checkPosition()!
    public Position next(Position p) throws InvalidPositionException, BoundaryViolationException{
        DNode node = checkPosition(p);
        DNode res = null;
        if(node != null){
            res = node.next();
        }
        else throw new BoundaryViolationException();
        return res;
    }

    //USE checkPosition()!
    public Position prev(Position p) throws InvalidPositionException, BoundaryViolationException{
        DNode node = checkPosition(p);
        DNode res = null;
        if(node != null){
            res = node.prev();
        }
        else throw new BoundaryViolationException();
        return res;

    }

    public void addFirst(Object o){
        DNode insert = new DNode(o, header, header.next());
        header.setNext(insert);
        insert.next().setPrev(insert);
        size++;
    }

    public void addLast(Object o){
        DNode insert = new DNode(o, trailer.prev(), trailer);
        trailer.setPrev(insert);
        insert.prev().setNext(insert);
        size++;
    }

    public void addAfter(Position p, Object o) throws InvalidPositionException{
        DNode node = checkPosition(p);
        if(node != null){
            DNode insert = new DNode(o, node, node.next());
            insert.next().setPrev(insert);
            insert.prev().setNext(insert);
            size++;
        }
        else throw new InvalidPositionException();
    }

    public void addBefore(Position p, Object o) throws InvalidPositionException{
        DNode node = checkPosition(p);
        if(node != null){
            DNode insert = new DNode(o, node.prev(), node);
            insert.next().setPrev(insert);
            insert.prev().setNext(insert);
            size++;
        }
        else throw new InvalidPositionException();
    }

    public Object remove(Position p){
        DNode remove = checkPosition(p);
        if(remove != null){
            remove.next().setPrev(remove.prev());
            remove.prev().setNext(remove.next());
            size--;
            return remove.element();
        }
        else return null;
    }

    public Object set(Position p, Object o){
        Object res = null;
        DNode node = checkPosition(p);
        if(node != null){
            res = node.element();
            node.setElement(o);
        }
        return res;
    }

    public String toString(){
        String res = "<DLList[";
        DNode node = header;
        while(node.next() != null && node.next() != trailer){
            res += node.next().toString() + ",";
            node = node.next();
        }
        if(!isEmpty()){
            res = res.substring(0, res.length() - 1);
        }

        return res + "]>";
    }

}